﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using Moq;
using System.IO;

namespace MvcWiki.Test.Repository.FileSystem.WikiPageFileSystemRepository
{
    public class GetWikiPageFacts
    {
        [Fact]
        public void Returns_WikiPage_By_Namespace_And_Name()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc" });

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            MvcWiki.Model.WikiPage wikiPage = repository.GetWikiPage("Namespace", "Page");
        }

        [Fact]
        public void Returns_WikiPage_With_WikiNamespace()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc" });

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            MvcWiki.Model.WikiPage wikiPage = repository.GetWikiPage("Namespace", "Page");

            Assert.Equal("Page", wikiPage.Name);
            Assert.Equal("Namespace", wikiPage.Namespace.Name);
        }

        [Fact]
        public void Reads_All_Files_With_Revisions()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc" });

            fileSystem.Setup(x => x.GetFiles("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc", "r---*.txt")).Returns(new string[] { });

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            MvcWiki.Model.WikiPage wikiPage = repository.GetWikiPage("Namespace", "Page");

            fileSystem.VerifyAll();
        }

        [Fact]
        public void Returns_WikiPage_With_WikiPageRevisions()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc" });

            var files = new string[] {
                "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc\\r---20090101010000.txt",
                "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc\\r---20090101010100.txt",
                "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc\\r---20090101010200.txt"
            };

            fileSystem.Setup(x => x.GetFiles("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc", "r---*.txt")).Returns(files);

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            MvcWiki.Model.WikiPage wikiPage = repository.GetWikiPage("Namespace", "Page");

            Assert.Equal<int>(3, wikiPage.Revisions.Count);
            Assert.Equal<DateTime>(new DateTime(2009, 01, 01, 01, 00, 00, DateTimeKind.Utc), wikiPage.Revisions[0].Created);
            Assert.Equal<DateTime>(new DateTime(2009, 01, 01, 01, 01, 00, DateTimeKind.Utc), wikiPage.Revisions[1].Created);
            Assert.Equal<DateTime>(new DateTime(2009, 01, 01, 01, 02, 00, DateTimeKind.Utc), wikiPage.Revisions[2].Created);
        }

        [Fact]
        public void Reads_Content_From_All_Revisions()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc" });

            var files = new string[] {
                "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc\\r---20090101010000.txt",
                "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc\\r---20090101010100.txt",
                "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc\\r---20090101010200.txt"
            };

            fileSystem.Setup(x => x.GetFiles("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc", "r---*.txt")).Returns(files);
            fileSystem.Setup(x => x.ReadFromFile("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc\\r---20090101010000.txt")).Returns("Revision content");
            fileSystem.Setup(x => x.ReadFromFile("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc\\r---20090101010100.txt")).Returns("Another revision content");
            fileSystem.Setup(x => x.ReadFromFile("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc\\r---20090101010200.txt")).Returns("Last revision content");

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            MvcWiki.Model.WikiPage wikiPage = repository.GetWikiPage("Namespace", "Page");

            Assert.Equal<string>("Revision content", wikiPage.Revisions[0].Content);
            Assert.Equal<string>("Another revision content", wikiPage.Revisions[1].Content);
            Assert.Equal<string>("Last revision content", wikiPage.Revisions[2].Content);

            fileSystem.VerifyAll();
        }

        [Fact]
        public void Throws_Exception_If_Namespace_Directory_Does_Not_Exists()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { });

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            Assert.Throws<MvcWiki.Exceptions.PageDoesNotExistException>(
                () => repository.GetWikiPage("Namespace", "Page"));
        }

        [Fact]
        public void Throws_Exception_If_Page_Directory_Does_Not_Exists()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { });

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            Assert.Throws<MvcWiki.Exceptions.PageDoesNotExistException>(
                () => repository.GetWikiPage("Namespace", "Page"));
        }

        [Fact]
        public void Returns_WikiPage_With_Id()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc" });

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            MvcWiki.Model.WikiPage wikiPage = repository.GetWikiPage("Namespace", "Page");

            Assert.Equal<string>("9f878f17-21bb-4fb1-a68e-3cd2c61201cc", wikiPage.Id.ToString());
        }

        [Fact]
        public void Calls_IWikiNamespaceRepsotory_GetWikiNamespace()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc" });
            
            var wikiPageRepository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            MvcWiki.Model.WikiPage wikiPage = wikiPageRepository.GetWikiPage("Namespace", "Page");

            wikiNamespaceRepository.VerifyAll();
        }

        [Fact]
        public void Returns_WikiPage_With_Revisions_Not_Null()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc" });

            fileSystem.Setup(x => x.GetFiles("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc", "r---*.txt")).Returns(new string[] { });

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            MvcWiki.Model.WikiPage wikiPage = repository.GetWikiPage("Namespace", "Page");

            Assert.NotNull(wikiPage.Revisions);
        }

        [Fact]
        public void Calls_IUnitOfWork_Selected()
        {
            var wikiNamespace = new MvcWiki.Model.WikiNamespace { Name = "Namespace" };

            var wikiNamespaceRepository = new Mock<MvcWiki.Repository.IWikiNamespaceRepository>();
            wikiNamespaceRepository.Setup(x => x.GetWikiNamespace("Namespace")).Returns(wikiNamespace);

            var repositoryFactory = new Mock<MvcWiki.Repository.IWikiRepositoryFactory>();
            repositoryFactory.Setup(x => x.GetWikiNamespaceRepository()).Returns(wikiNamespaceRepository.Object);

            var unitOfWork = new Mock<MvcWiki.Repository.IUnitOfWork>();
            unitOfWork.Setup(x => x.Selected(It.IsAny<MvcWiki.Model.WikiPage>(), It.IsAny<MvcWiki.Repository.IUnitOfWorkPersistence>()));

            var fileSystem = new Mock<MvcWiki.Repository.FileSystem.IFileSystemWrapper>();
            fileSystem.Setup(x => x.GetDirectories("c:\\path", "Namespace---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc" });
            fileSystem.Setup(x => x.GetDirectories("c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc", "Page---*")).Returns(new string[] { "c:\\path\\Namespace---9f878f77-21bb-4fb1-a68e-3cd2c61201cc\\Page---9f878f17-21bb-4fb1-a68e-3cd2c61201cc" });

            var repository = new MvcWiki.Repository.FileSystem.WikiPageFileSystemRepository(repositoryFactory.Object, unitOfWork.Object, "c:\\path", fileSystem.Object);

            repository.GetWikiPage("Namespace", "Page");

            unitOfWork.VerifyAll();
        }
    }
}